/*
 * main.cpp
 *
 *  Created on: Jul 4, 2012
 *      Author: kevin
 */
// include files van DIT systeem
#include "akk/akkInclude.h"
#include<string>
#include<cstring>

#include<cstdio>
#include<cstdlib>
#include "BlockCache.h"
#include "FileSystem.h"
using namespace std;


void readSuper(fstream* disk) {
	int disksize = 0;
	short i_size;
	long f_size;
	byte* superBlock = new byte[DBLKSIZ];

	disk->seekg(0, ios::end);
	disksize = disk->tellg();

	disk->seekg(DBLKSIZ * 1);
	disk->read((char*) superBlock, DBLKSIZ);
	i_size = getshort(superBlock, 0);
	f_size = getlong(superBlock, 2);
	cout << "disksize: " << disksize << "b" << endl;
	cout << "i-size : " << i_size << " blocks" << endl;
	cout << "f-size : " << f_size << " blocks" << endl;

	int freecount = getshort(superBlock, 6);
	int offset = 8;
	cout << "freecount: " << freecount << endl;
	for (int i = 0; i < freecount; i ++) {
		cout << "vrij block: " << getlong(superBlock, offset) << endl;
		offset += 4;
	}

	offset= 8 + 4* NICFREE;
	int nextShort = getshort(superBlock, offset);
	cout << "next short: " << nextShort << endl;
	offset += 2;
	for (int i = 0; i < nextShort; i ++)
	{
			cout << "gelezen uit nextshort: " << getshort(superBlock, offset) << endl;
			offset += 2;
	}
}

dinode getInode(byte* block, int blockOffset)
{
	int byteOffset = blockOffset * INSIZ;
	int offset = byteOffset;
	dinode inode;

	inode.di_mode = getshort(block, offset); //2Bytes
	offset += 2; // shift offset by 2 Bytes
	inode.di_nlink = getshort(block, offset); //2Bytes
	offset += 2; // shift offset by 2 Bytes
	inode.di_uid = getshort(block, offset); //2Bytes
	offset += 2; // shift offset by 2 Bytes
	inode.di_gid = getshort(block, offset); //2Bytes
	offset += 2; // shift offset by 2 Bytes
	inode.di_size = getlong(block, offset); //4Bytes
	offset += 4; // shift offset by 4 Bytes
	memcpy(inode.di_addr, block+offset, 40);
	offset += 40; // shift offset by 40 Bytes
	inode.di_atime = getlong(block, offset);
	offset += 4; // shift offset by 4 Bytes
	inode.di_mtime = getlong(block, offset);
	offset += 4; // shift offset by 4 Bytes
	inode.di_ctime = getlong(block, offset);
	offset += 4; // shift offset by 4 Bytes


	return inode;
}

void printTime(time_t atime){
	printf ( "%s", ctime (&atime) );

}

void printSize(off_x size){
	cout << size << "\t";
}

void printLink(short links){
	cout << links << "\t";
}


void printInodePermissions(dinode inode)
{

	char permissions[] = {"----------"};

	short maskedmode = inode.di_mode & X_IFMT;
	if(maskedmode ==  X_IFIFO)permissions[0] = 'f';
	else if(maskedmode ==  X_IFCHR)permissions[0] = 'f';
	else if(maskedmode ==  X_IFBLK)permissions[0] = 'b';
	else if(maskedmode ==  X_IFMPC)permissions[0] = 'm';
	else if(maskedmode ==  X_IFDIR)permissions[0] = 'd';
	else if(maskedmode ==  X_IFMPB)permissions[0] = 's';
	else if(maskedmode ==  X_IFREG)permissions[0] = 'r';

	if(inode.di_mode & X_IUREAD)permissions[1] = 'r';
	if(inode.di_mode & X_IUWRITE)permissions[2] = 'w';
	if(inode.di_mode & X_IUEXEC)permissions[3] = 'x';
	if(inode.di_mode & X_IGREAD)permissions[4] = 'r';
	if(inode.di_mode & X_IGWRITE)permissions[5] = 'w';
	if(inode.di_mode & X_IGEXEC)permissions[6] = 'x';
	if(inode.di_mode & X_IOREAD)permissions[7] = 'r';
	if(inode.di_mode & X_IOWRITE)permissions[8] = 'w';
	if(inode.di_mode & X_IOEXEC)permissions[9] = 'x';

	cout << permissions << "\t";
}

void printName(byte addr[40]){
	int offset  = 0;

	for(int i = 0; i < NADDR; i++)
	{
		cout << "convert: " << getlong3(addr, offset) << endl;
		offset += 3;
	}


}

void printDirectory(direct directory)
{
	cout << directory.d_ino << " | " << directory.d_name << endl;
}

//direct getDirect(block block, int position)
//{
//	direct dir;
//	int offset = position * 16;// size of directory entry (14 for name + 2 for ino_x)
//	dir.d_ino = getshort(block.bytes, offset);
//	memcpy(dir.d_name, block.bytes + offset + 2, 14);
//	return dir;
//}
//
//void readDirectory(ifstream* disk, int blocknumber)
//{
//	block b = BlockCache::readBlock(disk, blocknumber);
//	for(int i = 0; i < 32; i++)//32 is 512 / 16 which is the size of a directory entry
//	{
//		direct dir = getDirect(b, i);
//		if(dir.d_ino != 0)printDirectory(dir);
//	}
//
//}




void printInode(dinode inode, int inodeNumber){
	cout <<	"inum\tnlink\tmode\t\tsize\tdate-last-modified\t\tname" << endl;
	cout << inodeNumber << "\t";
	printLink(inode.di_nlink);
	printInodePermissions(inode);
	printSize(inode.di_size);
	printTime(inode.di_mtime);
	printName(inode.di_addr);

}

void printOneInode(dinode inode, int inodeNumber)
{

	cout << "Inode: " << inodeNumber << endl; //TODO name
	char type[32];
	char mode[32];
	sprintf(type, "%o", (inode.di_mode & X_IFMT));
	sprintf(mode, "%o", (inode.di_mode & 0007777));

	cout << "mode=" << mode << " ";
	printInodePermissions(inode);
	cout << "type=";


}


void readInode(fstream* disk, int number)
{
	byte* block = new byte[DBLKSIZ];
	int blocknumber = itod(number);
	cout << "blocknumber " << blocknumber << endl;
	disk->seekg(( blocknumber) * DBLKSIZ );
	disk->read((char*)block, DBLKSIZ);
	int offset = itoo(number);
	cout << "offset " << offset << endl;

	dinode inode = getInode(block, offset);
	delete block;
	printOneInode(inode, number);
	//printInode(inode, number);
}



int main() {
//	fstream* floppy = new fstream();
//	floppy->open("floppy/floppie", ios::binary);



	FileSystem* f = new FileSystem("floppy/floppie");
	cout << "free " << f->getFreeSpace() << endl;


	f->freeBlock(302);
//
	cout << "free " << f->getFreeSpace() << endl;

	delete f;

//	readSuper(floppy);
//	readInode(floppy, 107);
//	readDirectory(floppy, 60);
//	readDirectory(floppy, 1422);

	//TODO verwijder


//	delete floppy;


	return 0;
}
